Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gallery block: convert gallery to a wrapper around the core image block #24039

Closed
wants to merge 20 commits into from

Conversation

glendaviesnz
Copy link
Contributor

@glendaviesnz glendaviesnz commented Jul 20, 2020

Description

This is a PoC to explore the feasibility of moving the Gallery block to be a wrapper around the Image block.

Related to #11436 & Automattic/jetpack#11794 (comment)

Initial work has not highlighted any major technical issues that would make this approach unfeasible.

Things left to implement:

  • Tidy up of css to remove redundant selectors and match existing gallery layout more accurately
  • Reimplement the image size changing
  • Correctly apply the 'Link to' attribute to nested images on change
  • Deprecations/Migrations

How has this been tested?

Just manual tested currently during feedback phase.

innerblock-gallery

@glendaviesnz glendaviesnz added the [Block] Gallery Affects the Gallery Block - used to display groups of images label Jul 20, 2020
@glendaviesnz glendaviesnz self-assigned this Jul 20, 2020
@github-actions
Copy link

github-actions bot commented Jul 20, 2020

Size Change: -3.02 kB (0%)

Total Size: 1.17 MB

Filename Size Change
build/annotations/index.js 3.52 kB +4 B (0%)
build/block-directory/index.js 8.55 kB +1 B
build/block-editor/index.js 129 kB +1 B
build/block-library/index.js 133 kB -2.39 kB (1%)
build/block-library/style-rtl.css 7.32 kB -331 B (4%)
build/block-library/style.css 7.33 kB -329 B (4%)
build/blocks/index.js 47.5 kB +4 B (0%)
build/core-data/index.js 12 kB +2 B (0%)
build/data/index.js 8.61 kB +3 B (0%)
build/edit-post/index.js 306 kB +1 B
build/edit-widgets/index.js 21.4 kB +2 B (0%)
build/editor/index.js 45.5 kB +5 B (0%)
build/keyboard-shortcuts/index.js 2.39 kB +4 B (0%)
build/nux/index.js 3.27 kB +1 B
build/redux-routine/index.js 2.85 kB +2 B (0%)
build/rich-text/index.js 13 kB +3 B (0%)
ℹ️ View Unchanged
Filename Size Change
build/a11y/index.js 1.14 kB 0 B
build/api-fetch/index.js 3.35 kB 0 B
build/autop/index.js 2.72 kB 0 B
build/blob/index.js 668 B 0 B
build/block-directory/style-rtl.css 943 B 0 B
build/block-directory/style.css 942 B 0 B
build/block-editor/style-rtl.css 10.9 kB 0 B
build/block-editor/style.css 10.9 kB 0 B
build/block-library/editor-rtl.css 8.65 kB 0 B
build/block-library/editor.css 8.65 kB 0 B
build/block-library/theme-rtl.css 741 B 0 B
build/block-library/theme.css 741 B 0 B
build/block-serialization-default-parser/index.js 1.78 kB 0 B
build/block-serialization-spec-parser/index.js 3.1 kB 0 B
build/components/index.js 169 kB 0 B
build/components/style-rtl.css 15.3 kB 0 B
build/components/style.css 15.3 kB 0 B
build/compose/index.js 9.42 kB 0 B
build/data-controls/index.js 685 B 0 B
build/date/index.js 31.9 kB 0 B
build/deprecated/index.js 772 B 0 B
build/dom-ready/index.js 568 B 0 B
build/dom/index.js 4.42 kB 0 B
build/edit-navigation/index.js 10.7 kB 0 B
build/edit-navigation/style-rtl.css 868 B 0 B
build/edit-navigation/style.css 871 B 0 B
build/edit-post/style-rtl.css 6.29 kB 0 B
build/edit-post/style.css 6.27 kB 0 B
build/edit-site/index.js 20.5 kB 0 B
build/edit-site/style-rtl.css 3.71 kB 0 B
build/edit-site/style.css 3.72 kB 0 B
build/edit-widgets/style-rtl.css 3 kB 0 B
build/edit-widgets/style.css 3 kB 0 B
build/editor/editor-styles-rtl.css 492 B 0 B
build/editor/editor-styles.css 493 B 0 B
build/editor/style-rtl.css 3.85 kB 0 B
build/editor/style.css 3.84 kB 0 B
build/element/index.js 4.44 kB 0 B
build/escape-html/index.js 734 B 0 B
build/format-library/index.js 7.49 kB 0 B
build/format-library/style-rtl.css 547 B 0 B
build/format-library/style.css 548 B 0 B
build/hooks/index.js 1.74 kB 0 B
build/html-entities/index.js 621 B 0 B
build/i18n/index.js 3.54 kB 0 B
build/is-shallow-equal/index.js 710 B 0 B
build/keycodes/index.js 1.85 kB 0 B
build/list-reusable-blocks/index.js 3.02 kB 0 B
build/list-reusable-blocks/style-rtl.css 476 B 0 B
build/list-reusable-blocks/style.css 476 B 0 B
build/media-utils/index.js 5.12 kB 0 B
build/notices/index.js 1.69 kB 0 B
build/nux/style-rtl.css 671 B 0 B
build/nux/style.css 668 B 0 B
build/plugins/index.js 2.44 kB 0 B
build/primitives/index.js 1.34 kB 0 B
build/priority-queue/index.js 790 B 0 B
build/server-side-render/index.js 2.6 kB 0 B
build/shortcode/index.js 1.7 kB 0 B
build/token-list/index.js 1.24 kB 0 B
build/url/index.js 4.06 kB 0 B
build/viewport/index.js 1.74 kB 0 B
build/warning/index.js 1.13 kB 0 B
build/wordcount/index.js 1.17 kB 0 B

compressed-size-action

@ZebulanStanphill ZebulanStanphill added [Type] Technical Prototype Offers a technical exploration into an idea as an example of what's possible Needs Technical Feedback Needs testing from a developer perspective. labels Jul 20, 2020
// The id value is stored in a data attribute, so when the
// block is parsed it's converted to a string. Converting
// to a string here ensures it's type is consistent.
id: toString( newImage.id ),
} ) ),
columns: columns ? Math.min( newImages.length, columns ) : columns,
} );

replaceInnerBlocks( clientId, newBlocks );
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may need to be replaced with getBlocksByClientId and insertBlocks to compare what is already in the gallery with what is passed back by media dialog if we want to preserve sort order changes between updates from the media browser

@glendaviesnz glendaviesnz changed the title [WIP] - moving gallery to a wrapper around the core image block Gallery block: convert gallery to a wrapper around the core image block Jul 22, 2020
@glendaviesnz
Copy link
Contributor Author

glendaviesnz commented Jul 23, 2020

@mapk, @senadir, @talldan, @afercia, @ZebulanStanphill, @paaljoachim - what are your thoughts on this as a potential way forward with consistency between the image and gallery blocks. This seems to work reasonably well as a prototype, but no doubt there will be quite a bit of work getting the final pieces sorted, particularly deprecations, so would be good to get some idea of how feasible it is to get this into core before we commit to finishing it off.

@paaljoachim paaljoachim added the Needs Design Feedback Needs general design feedback. label Jul 23, 2020
@paaljoachim
Copy link
Contributor

Hey Glen. This look really interesting. Inner child Image Blocks containing the Image Block sidebar settings and the parent Gallery Block with it's own sidebar settings. This seems to be the exact features I have mentioned in #11436
Awesome work!

@afercia
Copy link
Contributor

afercia commented Jul 23, 2020

@glendaviesnz thanks for the ping.

Conceptually, it makes sense to me that a Gallery is represented as a group of images. If that serves also the purpose to simplify things, then I'd totally second your proposal. 🙂

From an accessibility perspective, I see at least two big issues that need to be solved:

  • keyboard accessibility in the context of the block editor Navigation / Edit modes
  • semantical representation of the gallery

Keyboard
Testing this PR in its current state, it doesn't play very well with the way the block editor Navigation / Edit modes work.
When editing an image, that image is now a single block in "edit mode". I can't tab any longer to the other images. I now need to exit Edit mode and enter Navigation mode (by pressing Escape), then move to another image and enter Edit mode again.
This makes keyboard interaction very difficult and not intuitive.

In the current Gallery block, it is actually possible to tab through all the images and their controls because there's just one block.

Semantics:
In this PR, in both the editor and in the front end, the gallery is now a series of <figure> elements nested within a main <figure> element. Not sure that's ideal. The current implementation instead uses a wrapper <figure> element and then all the image <figure>s are in an unordered list.
Semantically, a gallery is a group of related images that's better represented by a list.
Also, a list automatically gives screen reader users the information about the amount of items and the position of the items, e.g:

  • list with 12 items
  • item 1 of 12
  • item 2 of 12
  • etc.
    I'd say that preserving the list both in the editor and in the front end is a must have.

@ZebulanStanphill
Copy link
Member

The list issue reminds me a lot of the discussion going on in #23915 right now with the Navigation block, where a similar issue has been encountered. Perhaps both may end up using the same solution, whatever that may be.

@mapk
Copy link
Contributor

mapk commented Jul 23, 2020

Wow! ❤️ Thanks for this PR! It's been talked about for along time now. :)

I couldn't get it working on my local env. When I switched to this branch, it would move all my content into a grid structure, not just the gallery. I'm not sure if that's something on my end though.

I've got some quick feedback based on the gif above:

  • How do we handle the Gallery block's "Link to" settings? Should we just remove the Gallery's setting there, or keep it, but allow it to be overwritten by the Image block's link settings?
  • Does the alignment on the Image block make sense in the Gallery grid?
  • The Image block movers should probably be horizontal movers (like the Nav block) instead of vertical movers.
  • Does it make sense to keep the Image block's style variations here? Probably. I can imagine some interesting layouts with circle images and rectangular images combined in a gallery.
  • Should the "Image size" setting remain at the gallery level, or stay on the Image block level?

@talldan
Copy link
Contributor

talldan commented Jul 24, 2020

The list issue reminds me a lot of the discussion going on in #23915 right now with the Navigation block, where a similar issue has been encountered. Perhaps both may end up using the same solution, whatever that may be.

@ZebulanStanphill That's so true, and I think while we might have managed to avoid the problem for the nav block, given it's an issue here as well it seems a valid use case for blocks. I don't know that it's something that can be avoided for galleries.

I couldn't get it working on my local env. When I switched to this branch, it would move all my content into a grid structure, not just the gallery. I'm not sure if that's something on my end though.

@mapk I also had this issue, but I think it's still possible to test the gallery if it's the only block in a post.

It seems to work pretty well from my testing. The tab behavior is an interesting one, because it's been designed this way to improve accessing the toolbar and sidebar. Arrow key nav seems to work in a grid like fashion as the table block does.

@ellatrix
Copy link
Member

Nice work!

@ZebulanStanphill
Copy link
Member

Does the alignment on the Image block make sense in the Gallery grid?

I'd say definitely not. The PR is already trying to disable that via block context. I haven't actually gotten around to testing the branch myself yet, though, so I don't know if it actually works or not.

The Image block movers should probably be horizontal movers (like the Nav block) instead of vertical movers.

Definitely agree.

Does it make sense to keep the Image block's style variations here? Probably. I can imagine some interesting layouts with circle images and rectangular images combined in a gallery.

Style variations could also be used to apply various CSS filters (e.g. grayscale, sepia, etc.), so I don't think there's any reason to disable style variations for the Image block in this context.

Should the "Image size" setting remain at the gallery level, or stay on the Image block level?

Again, we could use block context if we wanted to inherit this from the Gallery block. Perhaps we should still allow custom values per Image block, but have the Gallery block set the default.

@glendaviesnz
Copy link
Contributor Author

I couldn't get it working on my local env. When I switched to this branch, it would move all my content into a grid structure, not just the gallery. I'm not sure if that's something on my end though.

@mapk - woops, the css selector nesting was a bit broken but didn't notice as I only had a single gallery block on my test post, have pushed a fix for this. The CSS for the grid is not perfect yet, some of the rows display the wrong height ... will look at moving the items to a list as @afercia suggests before I tidy this up, but you should at least be able to get it to display correctly with other blocks on the page now.

@glendaviesnz
Copy link
Contributor Author

From an accessibility perspective, I see at least two big issues that need to be solved:

Thanks for this feedback, I will see if the issues you outline can be resolved before we go any further.

@@ -87,13 +88,20 @@ export function ImageEdit( {
width,
height,
sizeSlug,
isInGallery,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will switch this to a context

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps the context name should be generalized to something that could be reused in other blocks like the Navigation block, e.g. isInList or isListItem.

Copy link
Contributor Author

@glendaviesnz glendaviesnz Jul 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a context of isList as this seemed slightly more natural language wise, eg. if image context.isList then treat is as a list item ... but happy to revise if I am looking at it from the wrong angle.

Also, I till had to add an image attribute of isListItem still, but setting this based in context as I couldn't see any way to access the context in the save method, and we need to know there whether to wrap the image in an <li> or not as well as in edit ... let me know if I have missed a better way fo handling this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not entirely sure which way to go with isList vs isListItem myself. It would be good to get some more opinions on this.

The edit markup should match the save markup as much as possible, so if it's being wrapped in a <li> in one, the other should match.

I would think (but could be wrong) that there should already be a way to access block context from the JS save component. But if not, the attribute is a decent workaround for now until that gets implemented.

Copy link
Member

@ZebulanStanphill ZebulanStanphill Jul 28, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm now thinking we shouldn't be handling this via block context at all. See this comment. Of course, implementing a new InnerBlocks prop is outside the scope of this PR, so that task would have to be done in a separate PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would think (but could be wrong) that there should already be a way to access block context from the JS save

The docs seem to indicate that is is currently only accessible via JS in the edit method, and doing some debugging and looking through the code seems to confirm that, but let me if you come across a way of accessing context in the save method.

Comment on lines 79 to 81
<li className={ classes }>
<figure>{ figure }</figure>
</li>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On first glace, I would think that, similar to how the "block alignment" wrapping div works (see the code a few lines earlier), the classes should still be applied to the figure, rather than the li.

Additionally, I wonder what consequences this may have for styles targeting the wp-block-image class, since that could now apply to an li in some cases, rather than the figure. Either way, I suppose theme style issues are inevitable with this sort of massive change.

Looking at the code, it looks like alignment wrappers are specially handled by the BlockListBlock component to ensure the editor-only wp-block CSS class is applied to the alignment wrapper and not the wrapped contents.

Replicating the same behavior in this case would probably require a similar modification. But modifying that general component just for this one use-case would obviously be a hack.

However, if we ended up taking the hypothetical <InnerBlocks childWrapper="li" /> kind of approach instead of using block context, the block classes could stay on the figure with no problems.

Another point in favor of the InnerBlocks-prop approach: even if we generalize the block context name for this list-item wrapping, it's still left up to the individual blocks to implement the li wrapper, and it opens the door to inconsistent handling of where the block classes are put.

Additionally, the InnerBlocks-prop approach would allow this child-wrapper behavior to be generalized even further to cases where the wrapper could even have multiple levels, e.g. childWrapper={ MyWrapper } where MyWrapper is a component that returns something like <li><div>{ theChildBlock }</div></li>.

Another benefit would be that the child blocks would not need to be aware of the parent block to take advantage of this. The parent block would This would allow the Gallery block to more easily support 3rd-party image blocks without each of those blocks having to handle the li wrapping themselves.

Yet another benefit: with block context, something like isList would be passed down to not only direct children, but also children-of-children. Since the direct children may not themselves be lists, those children would have to override isList themselves to prevent their children from inheriting the same value. Unlike something like postId or postType, the child block wrapper is only relevant to the parent and its direct children. The InnerBlocks-prop approach doesn't have this problem.

Ultimately, the list-element wrapper feels more like a part of the parent, rather than the child. Though implementing an InnerBlocks childWrapper prop may result in a slight increase to the complexity of InnerBlocks, it would solve the issue in one spot and prevent other blocks from having to reimplement it over and over again, and it would remove the possibility for inconsistent handling of where the block classes get put.

I wasn't really sure before, but now I'm convinced that the InnerBlocks approach is the way to go.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeh, an InnerBlocks childwrapper prop would be a nice tidy decoupled way to handle this ... do you have any plans to explore adding this to InnerBlocks?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's completely untested and doesn't work for React Native yet, but I went ahead and threw together #24232 to implement that very feature.

Try rebasing your branch off of mine. You should be able to use the prop like so:

<InnerBlocks __experimentalItemWrapper="li" />
<InnerBlocks.Content __experimentalItemWrapper="li" />

Let me know if it works.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, got sidetracked with other project work today, will try and give it a go tomorrow

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's okay; my branch had a bunch of obvious bugs until recently anyway. 😛

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just tested it out. When I refresh the editor, it just fails to load, with this JS error occurring:
image

It looks like the problem is happening at this line, which gets called as a result of this line.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed this issue, but still getting the failing block validation ... will try and take a closer look at it this week.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got as far as working out that it is something to do with adding __experimentalItemCallback to InnerBlocks.Content in the save method.

Without this the block saves and validates fine on editor refresh, but of course then the nested image blocks our not wrapped in li in the frontend.

With the callback added the nested image blocks are correctly wrapped in <li>s on the front end, but block validation fails when reloading the editor.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked into this, and I think the problem is not with your PR, but with the __experimentalItemCallback API; namely, I forgot to change any of the parsing code in #24232, so the editor doesn't know how to parse the post's comment-delimited HTML properly when the render callback API is used. See this comment. 😟

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whew, not just something simple/stupid that I was overlooking at least 😄

@glendaviesnz
Copy link
Contributor Author

This will be very broken now - just rebased in order to get to a point to start work on this again, but will probably close this PR soon and start a fresh one.

@paaljoachim
Copy link
Contributor

Sounds great, Glen! @glendaviesnz
Remember if we get this merged by the 20 October we will also be able to get this into WP 5.6.
I believe it will be helpful for many that one can create a link for each individual image inside the gallery.

@glendaviesnz
Copy link
Contributor Author

closing in favour of #25940

@glendaviesnz glendaviesnz deleted the try/nested-image-gallery branch October 8, 2020 03:00
@ellatrix
Copy link
Member

Also, a list automatically gives screen reader users the information about the amount of items and the position of the items, e.g:

  • list with 12 items
  • item 1 of 12
  • item 2 of 12

If it's on unordered list, why would order matter then?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Block] Gallery Affects the Gallery Block - used to display groups of images Needs Design Feedback Needs general design feedback. Needs Technical Feedback Needs testing from a developer perspective. [Type] Technical Prototype Offers a technical exploration into an idea as an example of what's possible
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants